using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Xml.Serialization;
using System.Xml;
using OnlinePlots.Diagrams;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows;
using System.Linq;
using System.Windows.Data;

namespace OnlinePlots.Plots.Elements
{
    /// <summary>
    /// Represents label strip element of a plot
    /// </summary>
    public class LabelStripElement : DiagramElement
    {
        /// <summary>
        /// Creates a new instance of label strip element
        /// </summary>
        public LabelStripElement()
            : base()
        {
        }

        new public static readonly DependencyProperty ZOrderProperty = DependencyProperty.Register(
                "ZOrder",
                typeof(int),
                typeof(LabelStripElement),
                new PropertyMetadata(300)
            );

        public static readonly DependencyProperty OpacityProperty = DependencyProperty.Register(
                        "Opacity",
                        typeof(double),
                        typeof(LabelStripElement),
                        new PropertyMetadata(1.0, new PropertyChangedCallback(OnOpacityPropertyChanged))
                    );

        /// <summary>
        /// Gets or sets opacity
        /// </summary>
        public double Opacity
        {
            get { return (double)GetValue(OpacityProperty); }
            set { SetValue(OpacityProperty, value); }
        }

        static protected void OnOpacityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DiagramElement el = d as DiagramElement;
            el.NotifyPropertyChanged("Opacity");
        }

        public static readonly DependencyProperty VerticalProperty = DependencyProperty.Register(
                        "Vertical",
                        typeof(bool),
                        typeof(LabelStripElement),
                        new PropertyMetadata(false, new PropertyChangedCallback(OnVerticalPropertyChanged))
                    );

        /// <summary>
        /// Gets or sets flag indicating if labels text direction is vertical
        /// </summary>
        public Boolean Vertical
        {
            get { return (bool)GetValue(VerticalProperty); }
            set { SetValue(VerticalProperty, value); }
        }

        static protected void OnVerticalPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            LabelStripElement el = d as LabelStripElement;
            if (el != null) 
            {
                el.Labels.ToList().ForEach(text => {
                        RotateTransform rt = text.RenderTransform as RotateTransform;
                        if ((bool)e.NewValue)
                        {
                            if (rt == null)
                                text.RenderTransform = new RotateTransform() { Angle = 90 };
                            else
                                rt.Angle = 90;
                        }
                        else
                        {
                            if (rt != null) rt.Angle = 0;
                        }
                    });
            }
        }

        public static readonly DependencyProperty AlignmentProperty = DependencyProperty.Register(
                        "Alignment",
                        typeof(TextAlignment),
                        typeof(LabelStripElement),
                        new PropertyMetadata(TextAlignment.Right, new PropertyChangedCallback(OnAlignmentPropertyChanged))
                    );

        /// <summary>
        /// Gets or sets alignment of labels
        /// </summary>
        public TextAlignment Alignment
        {
            get { return (TextAlignment)GetValue(AlignmentProperty); }
            set { SetValue(AlignmentProperty, value); }
        }

        static protected void OnAlignmentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DiagramElement el = d as DiagramElement;
            el.NotifyPropertyChanged("Alignment");
        }

        public static readonly DependencyProperty FontProperty = DependencyProperty.Register(
                        "Font",
                        typeof(FontFamily),
                        typeof(LabelStripElement),
                        new PropertyMetadata(new FontFamily("Arial"), new PropertyChangedCallback(OnFontPropertyChanged))
                    );

        /// <summary>
        /// Gets or sets font of labels
        /// </summary>
        public FontFamily Font
        {
            get { return (FontFamily)GetValue(FontProperty); }
            set { SetValue(FontProperty, value); }
        }

        static protected void OnFontPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DiagramElement el = d as DiagramElement;
            el.NotifyPropertyChanged("Font");
        }

        public static readonly DependencyProperty SizeProperty = DependencyProperty.Register(
                        "Size",
                        typeof(double),
                        typeof(LabelStripElement),
                        new PropertyMetadata(13.0, new PropertyChangedCallback(OnSizePropertyChanged))
                    );

        /// <summary>
        /// Gets or sets size of labels
        /// </summary>
        public double Size
        {
            get { return (double)GetValue(SizeProperty); }
            set { SetValue(SizeProperty, value); }
        }

        static protected void OnSizePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DiagramElement el = d as DiagramElement;
            el.NotifyPropertyChanged("Size");
        }

        public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
                        "Brush",
                        typeof(Brush),
                        typeof(LabelStripElement),
                        new PropertyMetadata(new SolidColorBrush(Colors.Blue), new PropertyChangedCallback(OnForegroundPropertyChanged))
                    );

        /// <summary>
        /// Gets or sets color of label text
        /// </summary>
        public Brush Foreground
        {
            get { return (Brush)GetValue(ForegroundProperty); }
            set { SetValue(ForegroundProperty, value); }
        }

        static protected void OnForegroundPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DiagramElement el = d as DiagramElement;
            el.NotifyPropertyChanged("Foreground");
        }

        public static readonly DependencyProperty MarginProperty = DependencyProperty.Register(
                        "Margin",
                        typeof(Thickness),
                        typeof(LabelStripElement),
                        new PropertyMetadata(new Thickness(1), new PropertyChangedCallback(OnMarginPropertyChanged))
                    );

        /// <summary>
        /// Gets or sets margin of label text inside of label rectangle
        /// </summary>
        public Thickness Margin
        {
            get { return (Thickness)GetValue(MarginProperty); }
            set { SetValue(MarginProperty, value); }
        }

        static protected void OnMarginPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DiagramElement el = d as DiagramElement;
            el.NotifyPropertyChanged("Margin");
        }

        internal void AddLabel(Point position, double value, String text)
        {
            TextBlock newLabel = new TextBlock()
            {
                Text = text,
                Tag = value
            };
            Canvas.SetLeft(newLabel, position.X);
            Canvas.SetTop(newLabel, position.Y);

            newLabel.SetBinding(TextBlock.MarginProperty, new Binding() { Source = Margin });
            newLabel.SetBinding(TextBlock.TextAlignmentProperty, new Binding() { Source = Alignment });
            newLabel.SetBinding(TextBlock.FontFamilyProperty, new Binding() { Source = Font });
            newLabel.SetBinding(TextBlock.FontSizeProperty, new Binding() { Source = Size });
            newLabel.SetBinding(TextBlock.ForegroundProperty, new Binding() { Source = Foreground });
            newLabel.SetBinding(TextBlock.OpacityProperty, new Binding() { Source = Opacity });
            newLabel.SetBinding(Canvas.ZIndexProperty, new Binding() { Source = ZOrder });

            if (Vertical)
                newLabel.RenderTransform = new RotateTransform() { Angle = -90 };

            shapes.Add(newLabel);
        }

        /// <summary>
        /// Gets all label shapes associated with the element
        /// </summary>
        public ReadOnlyCollection<TextBlock> Labels
        {
            get
            {
                return shapes.Cast<TextBlock>().ToList().AsReadOnly();
            }
        }
    }
}
